/*
 * Copyright (c) 2022, IMMORTA Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * - Neither the name of IMMORTA Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdbool.h>
#include "system_IM94.h"
#include "device_registers.h"
#include "clock_drv.h"

/* ----------------------------------------------------------------------------
   -- Core clock
   ---------------------------------------------------------------------------- */

uint32_t g_systemCoreClock = DEFAULT_SYSTEM_CLOCK;

/*******************************************************************************
 *** Function Name : SystemInit
 *** Description   : This function disables the watchdog, enables FPU
 ***                 and the power mode protection if the corresponding feature macro
 ***                 is enabled. SystemInit is called from startup_device file
 ******************************************************************************/
void SystemInit(void)
{
    /**************************************************************************/
    /* CACHE DISABLE */
    /**************************************************************************/
#if (DISABLE_PCACHE)
    FLASH->CFGR &= ~FLASH_CFGR_PCACHEEN_Msk;
    FLASH->CFGR &= ~FLASH_CFGR_PPREEN_Msk;
    (void)FLASH->CFGR;
    FLASH->CFGR |= FLASH_CFGR_PCACHECLR_Msk;
#endif /* (DISABLE_PCACHE) */

    /**************************************************************************/
    /* FPU settings */
    /**************************************************************************/
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
    SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); /* set CP10 and CP11 Full Access */
#endif

    /**************************************************************************/
    /* WDOG DISABLE */
    /**************************************************************************/
#if (DISABLE_WDOG)

    /* WDG Unlock */
    WDG->CNT = CONFIG_WDG_UNLOCK_VALUE;
    /*The deummy read is used to make sure the unlock was completed. */
    (void)WDG->CNT;

    /* WDG Disable */
    WDG->CS = (uint32_t)((0U << WDG_CS_EN_Pos)     |
                         (1U << WDG_CS_UPDATE_Pos) |
                         (1U << WDG_CS_CLK_Pos));
#endif /* (DISABLE_WDOG) */
}

/*******************************************************************************
 *** Function Name : SystemCoreClockUpdate
 *** Description   : This function must be called whenever the core clock is changed
 ***                 during program execution. It evaluates the clock register settings
 ***                 and calculates the current core clock
 ******************************************************************************/
void SystemCoreClockUpdate(void)
{
    uint32_t ahbClkInHz = 0U;
    uint32_t ahbClkInMHz = 0U;

    /* Acquire and update system core clock */
    (void)CLOCK_GetFreq(CLK_SYS, &g_systemCoreClock);

    /* Acquire ahb clock */
    (void)CLOCK_GetFreq(CLK_AHB, &ahbClkInHz);
    ahbClkInMHz = (ahbClkInHz / 1000000U);

    /* Set flash frequency */
    FLASH->CFGR &= ~(0xFFFFU << 16U);
    FLASH->CFGR |= (ahbClkInMHz << 16U);
}

/*******************************************************************************
 *** Function Name : System_SuspendAllInterrupts
 *** Description   : Suspend all interrupts
 ******************************************************************************/
#if defined ( __CC_ARM )
__asm uint32_t System_SuspendAllInterrupts(void)
{
    mrs r0, PRIMASK
    cpsid i
    bx lr
}
#elif defined (__GNUC__) || ( __ICCARM__ )
__attribute__((__used__)) uint32_t System_SuspendAllInterrupts(void)
{
    volatile uint32_t mask = 0;

    /*lint -save -e522 -e10 suppress mirsa message caused by assembly */
    __asm volatile(
        " mrs %0, PRIMASK\n"
        " cpsid i\n"
        : "=r"(mask)
        :
        : "memory"
    );
    /*lint -restore */

    return mask;
}
#endif
/*******************************************************************************
 *** Function Name : System_ResumeAllInterrupts
 *** Description   : Resume all interrupts
 ******************************************************************************/
#if defined ( __CC_ARM )
__asm void System_ResumeAllInterrupts(uint32_t ulMask)
{
    msr PRIMASK, r0
    bx lr
}
#elif defined (__GNUC__) || (__ICCARM__)
__attribute__((__used__)) __attribute__((noinline))
void System_ResumeAllInterrupts(volatile uint32_t ulMask)
{
    /*lint -save -e522 -e10 suppress mirsa message caused by assembly */
    __asm volatile(
        " msr PRIMASK, r0\n"
        ::: "memory"
    );
    /*lint -restore */
}
#endif

/*******EOF********************************************************************/
